home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / Manuels & Misc / Assembly / AOA.ZIP / CH21 / TRANSMIT.ASM < prev   
Encoding:
Assembly Source File  |  1994-07-26  |  12.1 KB  |  475 lines

  1. ; TRANSMIT.ASM
  2. ;
  3. ; This program is the transmitter portion of the programs that transmit files
  4. ; across a Laplink compatible parallel cable.
  5. ;
  6. ; This program assumes that the user want to use LPT1: for transmission.
  7. ; Adjust the equates, or read the port from the command line if this
  8. ; is inappropriate.
  9.  
  10.         .286
  11.         .xlist
  12.         include     stdlib.a
  13.         includelib    stdlib.lib
  14.         .list
  15.  
  16.  
  17. dseg        segment    para public 'data'
  18.  
  19. TimeOutConst    equ    4000            ;About 1 min on 66Mhz 486.
  20. PrtrBase    equ    10            ;Offset to LPT1: adrs.
  21.  
  22. MyPortAdrs    word    ?            ;Holds printer port address.
  23. FileHandle    word    ?            ;Handle for output file.
  24. FileBuffer    byte    512 dup (?)        ;Buffer for incoming data.
  25.  
  26. FileSize    dword    ?            ;Size of incoming file.
  27. FileNamePtr    dword    ?            ;Holds ptr to filename
  28.  
  29. dseg        ends
  30.  
  31. cseg        segment    para public 'code'
  32.         assume    cs:cseg, ds:dseg
  33.  
  34.  
  35. ; TestAbort-    Check to see if the user has pressed ctrl-C and wants to
  36. ;        abort this program.  This routine calls BIOS to see if the
  37. ;        user has pressed a key.  If so, it calls DOS to read the
  38. ;        key (function AH=8, read a key w/o echo and with ctrl-C
  39. ;        checking).
  40.  
  41. TestAbort    proc    near
  42.         push    ax
  43.         push    cx
  44.         push    dx
  45.         mov    ah, 1
  46.         int    16h            ;See if keypress.
  47.         je    NoKeyPress        ;Return if no keypress.
  48.         mov    ah, 8            ;Read char, chk for ctrl-C.
  49.         int    21h            ;DOS aborts if ctrl-C.
  50. NoKeyPress:    pop    dx
  51.         pop    cx
  52.         pop    ax
  53.         ret
  54. TestAbort    endp
  55.  
  56.  
  57.  
  58. ; SendByte-    Transmit the byte in AL to the receiving site four bits
  59. ;        at a time.
  60.  
  61. SendByte    proc    near
  62.         push    cx
  63.         push    dx
  64.         mov    ah, al        ;Save byte to xmit.
  65.  
  66.         mov    dx, MyPortAdrs    ;Base address of LPT1: port.
  67.  
  68. ; First, just to be sure, write a zero to bit #4.  This reads as a one
  69. ; in the busy bit of the receiver.
  70.  
  71.         mov    al, 0
  72.         out    dx, al        ;Data not ready yet.
  73.  
  74. ; Wait until the receiver is not busy.  The receiver will write a zero
  75. ; to bit #4 of its data register while it is busy. This comes out as a
  76. ; one in our busy bit (bit 7 of the status register).  This loop waits
  77. ; until the receiver tells us its ready to receive data by writing a
  78. ; one to bit #4 (which we read as a zero).  Note that we check for a
  79. ; ctrl-C every so often in the event the user wants to abort the
  80. ; transmission.
  81.  
  82.         inc    dx        ;Point at status register.
  83. W4NBLp:        mov    cx, 10000
  84. Wait4NotBusy:    in    al, dx        ;Read status register value.
  85.         test    al, 80h        ;Bit 7 = 1 if busy.
  86.         loopne    Wait4NotBusy    ;Repeat while busy, 10000 times.
  87.         je    ItsNotbusy    ;Leave loop if not busy.
  88.         call    TestAbort    ;Check for Ctrl-C.
  89.         jmp    W4NBLp
  90.  
  91. ; Okay, put the data on the data lines:
  92.  
  93. ItsNotBusy:    dec    dx        ;Point at data register.
  94.         mov    al, ah        ;Get a copy of the data.
  95.         and    al, 0Fh        ;Strip out H.O. nibble
  96.         out    dx, al        ;"Prime" data lines, data not avail.
  97.         jmp    $+2        ;Short delay to allow the data time
  98.         jmp    $+2        ; to stablize on the data lines.
  99.         or    al, 10h        ;Turn data available on.
  100.         out    dx, al        ;Send data w/data available strobe.
  101.  
  102. ; Wait for the acknowledge from the receiving site.  Every now and then
  103. ; check for a ctrl-C so the user can abort the transmission program from
  104. ; within this loop.
  105.  
  106.         inc    dx        ;Point at status register.
  107. W4ALp:        mov    cx, 10000    ;Times to loop between ctrl-C checks.
  108. Wait4Ack:    in    al, dx        ;Read status port.
  109.         test    al, 80h        ;Ack = 1 when rcvr acknowledges.
  110.         loope    Wait4Ack    ;Repeat 10000 times or until ack.
  111.         jne    GotAck        ;Branch if we got an ack.
  112.         call    TestAbort    ;Every 10000 calls, check for a
  113.         jmp    W4ALp        ; ctrl-C from the user.
  114.  
  115. ; Send the data not available signal to the receiver:
  116.  
  117. GotAck:        dec    dx        ;Point at data register.
  118.         mov    al, 0        ;Write a zero to bit 4, this appears
  119.         out    dx, al        ; as a one in the rcvr's busy bit.
  120.  
  121.  
  122. ; Okay, on to the H.O. nibble:
  123.  
  124.         inc    dx        ;Point at status register.
  125. W4NB2:        mov    cx, 10000    ;10000 calls between ctrl-C checks.
  126. Wait4NotBusy2:    in    al, dx        ;Read status register.
  127.         test    al, 80h        ;Bit 7 = 1 if busy.
  128.         loopne    Wait4NotBusy2    ;Loop 10000 times while busy.
  129.         je    NotBusy2    ;H.O. bit clear (not busy)?
  130.         call    TestAbort    ;Check for ctrl-C.
  131.         jmp    W4NB2
  132.  
  133. ; Okay, put the data on the data lines:
  134.  
  135. NotBusy2:    dec    dx        ;Point at data register.
  136.         mov    al, ah        ;Retrieve data to get H.O. nibble.
  137.         shr    al, 4        ;Move H.O. nibble to L.O. nibble.
  138.         out    dx, al        ;"Prime" data lines.
  139.         or    al, 10h        ;Data + data available strobe.
  140.         out    dx, al        ;Send data w/data available strobe.
  141.  
  142. ; Wait for the acknowledge from the receiving site:
  143.  
  144.         inc    dx        ;Point at status register.
  145. W4A2Lp:        mov    cx, 10000
  146. Wait4Ack2:    in    al, dx        ;Read status port.
  147.         test    al, 80h        ;Ack = 1
  148.         loope    Wait4Ack2    ;While while no acknowledge
  149.         jne    GotAck2        ;H.O. bit = 1 (ack)?
  150.         call    TestAbort    ;Check for ctrl-C
  151.         jmp    W4A2Lp
  152.  
  153. ; Send the data not available signal to the receiver:
  154.  
  155. GotAck2:    dec    dx        ;Point at data register.
  156.         mov    al, 0        ;Output a zero to bit #4 (that
  157.         out    dx, al        ; becomes busy=1 at rcvr).
  158.  
  159.         mov    al, ah        ;Restore original data in AL.
  160.         pop    dx
  161.         pop    cx
  162.         ret
  163. SendByte    endp
  164.  
  165.  
  166.  
  167. ; Synchronization routines:
  168. ;
  169. ; Send0s-    Transmits a zero to the receiver site and then waits to
  170. ;        see if it gets a set of ones back.  Returns carry set if
  171. ;        this works, returns carry clear if we do not get a set of
  172. ;        ones back in a reasonable amount of time.
  173.  
  174. Send0s        proc    near
  175.         push    cx
  176.         push    dx
  177.  
  178.         mov    dx, MyPortAdrs
  179.  
  180.         mov    al, 0            ;Write the initial zero
  181.         out    dx, al            ; value to our output port.
  182.  
  183.         xor    cx, cx            ;Checks for ones 10000 times.
  184. Wait41s:    inc    dx            ;Point at status port.
  185.         in    al, dx            ;Read status port.
  186.         dec    dx            ;Point back at data port.
  187.         and    al, 78h            ;Mask input bits.
  188.         cmp    al, 78h            ;All ones yet?
  189.         loopne    Wait41s
  190.         je    Got1s            ;Branch if success.
  191.         clc                ;Return failure.
  192.         pop    dx
  193.         pop    cx
  194.         ret
  195.  
  196. Got1s:        stc                ;Return success.
  197.         pop    dx
  198.         pop    cx
  199.         ret
  200. Send0s        endp
  201.  
  202.  
  203. ; Send1s-    Transmits all ones to the receiver site and then waits to
  204. ;        see if it gets a set of zeros back.  Returns carry set if
  205. ;        this works, returns carry clear if we do not get a set of
  206. ;        zeros back in a reasonable amount of time.
  207.  
  208. Send1s        proc    near
  209.         push    cx
  210.         push    dx
  211.  
  212.         mov    dx, MyPortAdrs        ;LPT1: base address.
  213.  
  214.         mov    al, 0Fh            ;Write the "all ones"
  215.         out    dx, al            ; value to our output port.
  216.  
  217.         mov    cx, 0
  218. Wait40s:    inc    dx            ;Point at input port.
  219.         in    al, dx            ;Read the status port.
  220.         dec    dx            ;Point back at data port.
  221.         and    al, 78h            ;Mask input bits.
  222.         loopne    Wait40s            ;Loop until we get zero back.
  223.         je    Got0s            ;All zeros?  If so, branch.
  224.         clc                ;Return failure.
  225.         pop    dx
  226.         pop    cx
  227.         ret
  228.  
  229.  
  230. Got0s:        stc                ;Return success.
  231.         pop    dx
  232.         pop    cx
  233.         ret
  234. Send1s        endp
  235.  
  236.  
  237.  
  238.  
  239. ; Synchronize-    This procedure slowly writes all zeros and all ones to its
  240. ;        output port and checks the input status port to see if the
  241. ;        receiver site has synchronized.  When the receiver site
  242. ;        is synchronized, it will write the value 05h to its output
  243. ;        port.  So when this site sees the value 05h on its input
  244. ;        port, both sites are synchronized.  Returns with the
  245. ;        carry flag set if this operation is successful, clear if
  246. ;        unsuccessful.
  247.  
  248. Synchronize    proc    near
  249.         print
  250.         byte    "Synchronizing with receiver program"
  251.         byte    cr,lf,0
  252.  
  253.         mov    dx, MyPortAdrs
  254.  
  255.         mov    cx, TimeOutConst    ;Time out delay.
  256. SyncLoop:    call    Send0s            ;Send zero bits, wait for
  257.         jc    Got1s            ; ones (carry set=got ones).
  258.  
  259. ; If we didn't get what we wanted, write some ones at this point and see
  260. ; if we're out of phase with the receiving site.
  261.  
  262. Retry0:        call    Send1s            ;Send ones, wait for zeros.
  263.         jc    SyncLoop        ;Carry set = got zeros.
  264.  
  265. ; Well, we didn't get any response yet, see if the user has pressed ctrl-C
  266. ; to abort this program.
  267.  
  268. DoRetry:    call    TestAbort
  269.  
  270. ; Okay, the receiving site has yet to respond.  Go back and try this again.
  271.  
  272.         loop    SyncLoop
  273.  
  274. ; If we've timed out, print an error message and return with the carry
  275. ; flag clear (to denote a timeout error).
  276.  
  277.         print
  278.         byte    "Transmit: Timeout error waiting for receiver"
  279.         byte    cr,lf,0
  280.         clc
  281.         ret
  282.  
  283. ; Okay, we wrote some zeros and we got some ones.  Let's write some ones
  284. ; and see if we get some zeros.  If not, retry the loop.
  285.  
  286. Got1s:
  287.         call    Send1s            ;Send one bits, wait for
  288.         jnc    DoRetry            ; zeros (carry set=got zeros).
  289.  
  290. ; Well, we seem to be synchronized.  Just to be sure, let's play this out
  291. ; one more time.
  292.  
  293.         call    Send0s            ;Send zeros, wait for ones.
  294.         jnc    Retry0
  295.         call    Send1s            ;Send ones, wait for zeros.
  296.         jnc    DoRetry
  297.  
  298. ; We're syncronized.  Let's send out the 05h value to the receiving
  299. ; site to let it know everything is cool:
  300.  
  301.         mov    al, 05h            ;Send signal to receiver to
  302.         out    dx, al            ; tell it we're sync'd.
  303.  
  304.         xor    cx, cx            ;Long delay to give the rcvr
  305. FinalDelay:    loop    FinalDelay        ; time to prepare.
  306.  
  307.         print
  308.         byte    "Synchronized with receiving site"
  309.         byte    cr,lf,0
  310.         stc
  311.         ret
  312. Synchronize    endp
  313.  
  314.  
  315.  
  316. ; File I/O routines:
  317. ;
  318. ; GetFileInfo-    Opens the user specified file and passes along the file
  319. ;        name and file size to the receiving site.  Returns the
  320. ;        carry flag set if this operation is successful, clear if
  321. ;        unsuccessful.
  322.  
  323. GetFileInfo    proc    near
  324.  
  325. ; Get the filename from the DOS command line:
  326.  
  327.         mov    ax, 1
  328.         argv
  329.         mov    word ptr FileNamePtr, di
  330.         mov    word ptr FileNamePtr+2, es
  331.  
  332.         printf
  333.         byte    "Opening %^s\n",0
  334.         dword    FileNamePtr
  335.  
  336. ; Open the file:
  337.  
  338.         push    ds
  339.         mov    ax, 3D00h        ;Open for reading.
  340.         lds    dx, FileNamePtr
  341.         int    21h
  342.         pop    ds
  343.         jc    BadFile
  344.         mov    FileHandle, ax
  345.  
  346. ; Compute the size of the file (do this by seeking to the last position
  347. ; in the file and using the return position as the file length):
  348.  
  349.         mov    bx, ax            ;Need handle in BX.
  350.         mov    ax, 4202h        ;Seek to end of file.
  351.         xor    cx, cx            ;Seek to position zero
  352.         xor    dx, dx            ; from the end of file.
  353.         int    21h
  354.         jc    BadFile
  355.  
  356.         mov    word ptr FileSize, ax    ;Save file length
  357.         mov    word ptr FileSize+2, dx
  358.  
  359. ; Need to rewind file back to the beginning (seek to position zero):
  360.  
  361.         mov    bx, FileHandle        ;Need handle in BX.
  362.         mov    ax, 4200h        ;Seek to beginning of file.
  363.         xor    cx, cx            ;Seek to position zero
  364.         xor    dx, dx
  365.         int    21h
  366.         jc    BadFile
  367.  
  368.  
  369. ; Okay, transmit the good stuff over to the receiving site:
  370.  
  371.         mov    al, byte ptr FileSize        ;Send the file
  372.         call    SendByte            ; size over.
  373.         mov    al, byte ptr FileSize+1
  374.         call    SendByte
  375.         mov    al, byte ptr FileSize+2
  376.         call    SendByte
  377.         mov    al, byte ptr FileSize+3
  378.         call    SendByte
  379.  
  380.         les    bx, FileNamePtr            ;Send the characters
  381. SendName:    mov    al, es:[bx]            ; in the filename to
  382.         call    SendByte            ; the receiver until
  383.         inc    bx                ; we hit a zero byte.
  384.         cmp    al, 0
  385.         jne    SendName
  386.         stc                    ;Return success.
  387.         ret
  388.  
  389. BadFile:    print
  390.         byte    "Error transmitting file information:",0
  391.         puti
  392.         putcr
  393.         clc
  394.         ret
  395. GetFileInfo    endp
  396.  
  397.  
  398. ; GetFileData-    This procedure reads the data from the file and transmits
  399. ;        it to the receiver a byte at a time.
  400.  
  401. GetFileData    proc    near
  402.         mov    ah, 3Fh            ;DOS read opcode.
  403.         mov    cx, 512            ;Read 512 bytes at a time.
  404.         mov    bx, FileHandle        ;File to read from.
  405.         lea    dx, FileBuffer        ;Buffer to hold data.
  406.         int    21h            ;Read the data
  407.         jc    GFDError        ;Quit if error reading data.
  408.  
  409.         mov    cx, ax            ;Save # of bytes actually read.
  410.         jcxz    GFDDone            ; quit if at EOF.
  411.         lea    bx, FileBuffer        ;Send the bytes in the file
  412. XmitLoop:    mov    al, [bx]        ; buffer over to the rcvr
  413.         call    SendByte        ; one at a time.
  414.         inc    bx
  415.         loop    XmitLoop
  416.         jmp    GetFileData        ;Read rest of file.
  417.  
  418. GFDError:    print
  419.         byte    "DOS error #",0
  420.         puti
  421.         print
  422.         byte    " while reading file",cr,lf,0
  423. GFDDone:    ret
  424. GetFileData    endp
  425.  
  426.  
  427.  
  428. ; Okay, here's the main program that controls everything.
  429.  
  430. Main        proc
  431.         mov    ax, dseg
  432.         mov    ds, ax
  433.         meminit
  434.  
  435.  
  436. ; First, get the address of LPT1: from the BIOS variables area.
  437.  
  438.         mov    ax, 40h
  439.         mov    es, ax
  440.         mov    ax, es:[PrtrBase]
  441.         mov    MyPortAdrs, ax
  442.  
  443. ; See if we have a filename parameter:
  444.  
  445.         argc
  446.         cmp    cx, 1
  447.         je    GotName
  448.         print
  449.         byte    "Usage: transmit <filename>",cr,lf,0
  450.         jmp    Quit
  451.  
  452.  
  453.  
  454. GotName:    call    Synchronize    ;Wait for the transmitter program.
  455.         jnc    Quit
  456.  
  457.         call    GetFileInfo    ;Get file name and size.
  458.         jnc    Quit
  459.  
  460.         call    GetFileData    ;Get the file's data.
  461.  
  462. Quit:        ExitPgm            ;DOS macro to quit program.
  463. Main        endp
  464.  
  465. cseg        ends
  466.  
  467. sseg        segment    para stack 'stack'
  468. stk        byte    1024 dup ("stack   ")
  469. sseg        ends
  470.  
  471. zzzzzzseg    segment    para public 'zzzzzz'
  472. LastBytes    byte    16 dup (?)
  473. zzzzzzseg    ends
  474.         end    Main
  475.